<?php

/**
 * 版本管理控制器
 */
namespace Common\Util;

use Think\Exception;

class Version
{

    public $status_config = [
        "待发布",
        "已发布",
        "已作废"
    ];

    public $platform_config = [
        "Unkown",
        "IOS",
        "Android"
    ];

    private $app_update_url = [
       "unkown" => "https://xx.xx.com/#/unknow",#weizhi
       "ios" => "https://xx.xx.com/#/download",#ios
       "android" => "https://xx.xx.com/#/download",#Android
    ];

    private $ver_cache_list_key = "plf_app_ver_new_";

    public function __construct()
    {
        $config = C("APP_VERSION_UPDATE_URL");

        if( $config )
        {
            $this->app_update_url = array_merge( $this->app_update_url, $config );
        }

        $this->app_update_url[0] = $this->app_update_url['unkown'];
        $this->app_update_url[1] = $this->app_update_url['ios'];
        $this->app_update_url[2] = $this->app_update_url['android'];
    }


    /**
    * 添加版本时，版本号检查（大小、重复、格式等）
    * @return 如果错误返回false 否则返回转化为整数的版本号
    */ 
    public function ver_chk(  $ver = '', $platform = 1, $id = "" )
	{
	 
		if( ( !preg_match("/^[\d]{1,2}\.[\d]{1,2}$/",$ver) && !preg_match("/^[\d]{1,2}\.[\d]{1,2}\.[\d]{1,2}$/",$ver) ) || empty( $this->platform_config[$platform] ) )
			return FALSE;

		#转化为整数格式	
		$app_ver_num = $this->turn2Int($ver);

		#版本重复和大小检查
		$Appver = M('app_version');

		$where['app_ver_num'] = ["EGT",$app_ver_num];
        $where['platform'] = $platform;
        $where['status'] = ["lt",2];
		

		$v = $Appver->where($where)->order("id desc")->limit(2)->fetchSql(0)->select();

		if( 1 < count($v) )
			return FALSE;

		if( !$v || $v[0]['id'] == $id )
			return $app_ver_num;

		return FALSE;
	}

    /**
    * APP新版本检查
    * @param $ver 必填
    * @param $platform 必填 ios 1  安卓2
    * @return 如果没有新版本，返回false 否则返回新的版本信息
    */ 
    public function app_ver_chk(  $ver = '', $platform = 1 )
    {
        // S($this->ver_cache_list_key.$platform,null);
        $new_ver = S($this->ver_cache_list_key.$platform);

        if( !$new_ver )
        {
            #版本查询最新版
            $Appver = M('app_version');
            
            $where['platform'] = $platform;
            $where['status'] = 1;

            $new_ver = $Appver->where($where)->order("app_ver_num desc,app_ver_code desc")->find();
            if( $new_ver )
            {
                $new_ver['new_version_code'] = !empty($new_ver['app_ver_code']) ? $new_ver['app_ver_code'] : $Appver->where($where)->count();
                S($this->ver_cache_list_key.$platform,$new_ver);
            }

        }

        if( !$new_ver || empty($new_ver) )
            return FALSE;

        #转化为整数格式    
        $app_ver_num = $this->turn2Int($ver);  

        #版本大小判断
        if( $app_ver_num >= $new_ver['app_ver_num'] )
            return FALSE;

        return  [
                    "for_update"=> ($app_ver_num <= $new_ver['last_need_update_ver']) ? TRUE : FALSE,
                    "title" => $new_ver['update_tissue'],
                    "message" => $new_ver['update_desc'],
                    "new_version" => $new_ver['app_ver'],
                    "new_version_code" => $new_ver['new_version_code'],
                    "platform" => $this->platform_config[$platform],
                    "url" => $this->app_update_url[$platform],
                    "hint" => "有新的版本可以更新哦"
                ];
    }

	/**
    * 版本号转化为整数格式	
    * @param $ver 版本号 支持x.x.x和x.x格式
    * @param $len 版本号中每一段的最大长度 默认2
    * @return int 非法的版本号false 正确格式的版本号返回int
    */
	public function turn2Int( $ver = '', $len = 2 )
	{
        if( is_int($ver) )
            return $ver;

        if( !preg_match("/^[\d]{1,$len}\.[\d]{1,$len}\.[\d]{1,$len}$/",$ver) )
        {
            #不符合1.0.0格式的时候看看是否符合1.0格式
            if( !preg_match("/^[\d]{1,$len}\.[\d]{1,$len}$/",$ver) )
                return 0;
            #进行补位
            $ver = $ver.'.0';
        }

		$vers = explode(".",$ver);	
		
		$count = count( $vers );
		
		$res = 0;
		
		foreach( $vers as $k => $v )
		{
			$res +=	pow( 10, $len*($count - $k - 1) ) * intval($v);
		}
		unset($k);
		unset($v);

		return $res;
    }
    

    /**
    * 整数格式转化版本号
    * @param $ver int
    * @param $len 版本号中每一段的最大长度 默认2
    * @return string  版本号 支持x.x.x和x.x格式
    */
	public function int2Ver( $ver = '', $len = 2 )
	{
        if( empty($ver) || !preg_match("/\d+/",$ver) )
		return $ver;

        $str_len = strlen( (string)$ver );
        $sps = ceil( $str_len / $len );
        $sps = $sps < 3 ? 3 : $sps;
        $ver_arr = [];
        $i = 0;
        $ver = (int)$ver;
        while( $i < $sps ){
            $i++;
            $base = pow(10, $len );
            $ver_arr[] = $ver % $base;
            $ver = floor( $ver/$base );
        }
        
        #逆序
        $ver_arr  = array_reverse( $ver_arr );
    
        unset($k);
        unset($v);

        return implode(".",$ver_arr);
	}
 	

    /**
     * 添加新版本号
     * @param
     */
    public function add( $param )
    {
        if( empty( $param ) )
            throw new Exception("INVALID_PARAM",-1);

        if( !isset($param['platform']) || empty( $this->platform_config[ $param['platform'] ] ) )
            throw new Exception("平台选择错误",-1);

        if( !isset($param['app_ver']) )
            throw new Exception("版本号未设置",-1);

        $param["app_ver_num"] = $this->ver_chk( $param["app_ver"], $param['platform'] );

        if(  !$param["app_ver_num"] )
            throw new Exception("版本号设置错误",-1);

        if( !isset($param['app_ver_name']) || empty( $param['app_ver_name'] ) )
            throw new Exception("版本名称未设置",-1);

        if( !isset($param['download_url']) || empty( $param['download_url'] ) )
            throw new Exception("应用下载地址设置有误",-1);
        
        if( !preg_match('/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i',$param['download_url']) )
            throw new Exception("下载地址格式错误",-2);

        if( !isset($param['update_tissue']) || empty( $param['update_tissue'] ) )
            throw new Exception("版本更新提示未设置",-1);

        if( !isset($param['update_desc']) || empty( $param['update_desc'] ) )
            throw new Exception("版本更新说明未设置",-1);

        if( !isset($param['last_need_update_ver']) || !preg_match("/^[\d]{1,6}$/",$param['last_need_update_ver']) )
            throw new Exception("强制更新设置错误",-1);

        $param['status'] = isset($param['status']) && isset($this->status_config[$param['status']]) ? intval($param['status']) : 0;
        $param['remark'] = isset($param['remark']) ? $param['remark']: '';
        $param['creator'] = isset($param['creator']) ? intval($param['creator']) : 0 ;
        $param['publisher'] = isset($param['publisher']) ? intval($param['publisher']) : 0 ;
        $param['create_time'] = $param['update_time'] = time();
        $param["app_ver_code"] = !empty($param['app_ver_code']) ? $param['app_ver_code'] : 0;
        $Appver = M('app_version');

        $save = $Appver->add( $param );

        if( !$save )
        {
            throw new Exception("版本添加失败",-2);
        }

        if( $param['status'] == 1 )
        {
            S($this->ver_cache_list_key.$param['platform'],null);
        }

        return $param;
            
    }

    /**
     * 添加 
     *
     */
    public function update( $param )
    {
        if( empty( $param ) )
            throw new Exception("参数错误",-1);

        if( !isset($param['id']) || empty( $param['id'] ) )
            throw new Exception("参数错误",-2);

        if( !isset($param['platform']) || empty( $this->platform_config[ $param['platform'] ] ) )
            throw new Exception("平台选择错误",-2);

        if( !isset($param['app_ver']) )
            throw new Exception("版本号未设置",-2);

        $param["app_ver_num"] = $this->ver_chk( $param["app_ver"], $param['platform'], $param['id'] );

        if( !$param["app_ver_num"] )
            throw new Exception("版本号设置错误",-2);

        if( !isset($param['app_ver_name']) || empty( $param['app_ver_name'] ) )
            throw new Exception("版本名称未设置",-2);
        
        if( !isset($param['download_url']) || empty( $param['download_url'] ) )
            throw new Exception("应用下载地址设置有误",-1);
        
        if( !preg_match('/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i',$param['download_url']) )
            throw new Exception("下载地址格式错误",-2);

        if( !isset($param['update_tissue']) || empty( $param['update_tissue'] ) )
            throw new Exception("版本更新提示未设置",-2);

        if( !isset($param['update_desc']) || empty( $param['update_desc'] ) )
            throw new Exception("版本更新说明未设置",-2);

        if( !isset($param['last_need_update_ver']) || !preg_match("/^[\d]{1,6}$/",$param['last_need_update_ver']) )
            throw new Exception("强制更新设置错误",-2);

        $param['status'] = isset($param['status']) && isset($this->status_config[$param['status']]) ? intval($param['status']) : 0;
        $param['remark'] = isset($param['remark']) ? $param['remark']: '';

        if( isset($param['app_ver_code']) && !empty($param['app_ver_code']))
        {
            $param['app_ver_code'] = intval($param['app_ver_code']);
        }

        $Appver = M('app_version');

        #检查是否发布成功否则不允许更改
        $ver = $Appver->where([
            "id" => $param['id']
        ])->find();

        if( !$ver )
            throw new Exception("版本不存在",-2);

        if( 0 != $ver['status'] )
            throw new Exception("该版本已经发布或作废",-2);

        $save = $Appver->where([
            "id" => $param['id']
        ])->save( $param );

        if( $save === false )
        {
            throw new Exception("更新版本失败",-2);
        }

        if( $param['status'] == 1 )
        {
            S($this->ver_cache_list_key.$param['platform'],null);
        }

 
        return $param;
            
    }


    /**
    * 发布版本
    * @param id int
    * @param publisher int
    */ 
    public function publishVersion( $param )
    {

        if( empty($param) )
            throw new Exception("版本号未设置",-3);
        

        if( !isset($param['id']) )
            throw new Exception("版本未选择",-3);
        
        $Appver = M('app_version');

        #检查是否发布成功否则不允许更改
        $ver = $Appver->where([
            "id" => $param['id']
        ])->find();

        if( !$ver )
            throw new Exception("版本不存在",-2);

        if( 0 != $ver['status'] )
            throw new Exception("该版本已经发布或作废",-2);
        
        $check = $this->ver_chk( $ver["app_ver"], $ver['platform'], $ver['id'] );

        if( !$check )
            throw new Exception("版本号设置错误",-2);

        if( !preg_match('/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i',$ver['download_url']) )
            throw new Exception("下载地址格式错误",-2);
        
        $ver['status'] = 1;
        $ver['publisher'] = isset($param['publisher']) ? intval($param['publisher']) : 0 ;
        $ver['update_time'] = $ver['publish_time'] = time();

        $update = $Appver->where([
            "id" => $param["id"]
        ])->save($ver);

        if( $update === false )
        {
            throw new Exception("发布失败",-2);
        }

        $update2 = $Appver->where([
            "app_ver_num" => ['lt',$ver["app_ver_num"]],
            "platform" => $ver["platform"],
            "status" => 0,
        ])->save($ver);

        #删除缓存的新版本
        S($this->ver_cache_list_key.$param['platform'],null);

        return $ver;
    }


    /**
    * 删除版本
    * @param id int
    * @param publisher int
    */ 
    public function removeVersion( $param )
    {

        if( empty($param) )
            throw new Exception("版本号未设置",-3);
        

        if( !isset($param['id']) )
            throw new Exception("版本未选择",-3);
        
        $Appver = M('app_version');

        #检查是否发布成功否则不允许更改
        $ver = $Appver->where([
            "id" => $param['id']
        ])->find();

        if( !$ver )
            throw new Exception("版本不存在",-2);

        if( 0 != $ver['status'] )
            throw new Exception("该版本已经发布或作废",-2);
        
        $check = $this->ver_chk( $ver["app_ver"], $ver['platform'], $ver['id'] );

        if( !$check )
            throw new Exception("版本号设置错误",-2);

        $ver['status'] = 2;
        $ver['publisher'] = isset($param['publisher']) ? intval($param['publisher']) : 0 ;
        $ver['update_time'] = $ver['publish_time'] = time();

        $update = $Appver->where([
            "id" => $param["id"]
        ])->save($ver);

        if( $update === false )
        {
            throw new Exception("删除失败",-2);
        }

        #删除缓存的新版本
        S($this->ver_cache_list_key.$param['platform'],null);

        return $ver;
    }
}
